home *** CD-ROM | disk | FTP | other *** search
/ CD Actual Thematic 7: Programming / CDAT7.iso / Share / Codigo / hh / rsource.exe / Hexen Source / P_USER.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-22  |  34.3 KB  |  1,653 lines

  1.  
  2. //**************************************************************************
  3. //**
  4. //** p_user.c : Heretic 2 : Raven Software, Corp.
  5. //**
  6. //** $RCSfile: p_user.c,v $
  7. //** $Revision: 1.123 $
  8. //** $Date: 96/01/05 14:21:01 $
  9. //** $Author: bgokey $
  10. //**
  11. //**************************************************************************
  12.  
  13. #include "h2def.h"
  14. #include "p_local.h"
  15. #include "soundst.h"
  16.  
  17. void P_PlayerNextArtifact(player_t *player);
  18.  
  19. // Macros
  20.  
  21. #define MAXBOB 0x100000 // 16 pixels of bob
  22.  
  23. // Data
  24.  
  25. boolean onground;
  26. int newtorch; // used in the torch flicker effect.
  27. int newtorchdelta;
  28.  
  29. int PStateNormal[NUMCLASSES] = 
  30. {
  31.     S_FPLAY,
  32.     S_CPLAY,
  33.     S_MPLAY,
  34.     S_PIGPLAY
  35. };
  36.  
  37. int PStateRun[NUMCLASSES] = 
  38. {
  39.     S_FPLAY_RUN1,
  40.     S_CPLAY_RUN1,
  41.     S_MPLAY_RUN1,
  42.     S_PIGPLAY_RUN1
  43. };
  44.  
  45. int PStateAttack[NUMCLASSES] = 
  46. {
  47.     S_FPLAY_ATK1,
  48.     S_CPLAY_ATK1,
  49.     S_MPLAY_ATK1,
  50.     S_PIGPLAY_ATK1
  51. };
  52.  
  53. int PStateAttackEnd[NUMCLASSES] = 
  54. {
  55.     S_FPLAY_ATK2,
  56.     S_CPLAY_ATK3,
  57.     S_MPLAY_ATK2,
  58.     S_PIGPLAY_ATK1    
  59. };
  60.  
  61. int ArmorMax[NUMCLASSES] = { 20, 18, 16, 1 };
  62. /*
  63. ==================
  64. =
  65. = P_Thrust
  66. =
  67. = moves the given origin along a given angle
  68. =
  69. ==================
  70. */
  71.  
  72. void P_Thrust(player_t *player, angle_t angle, fixed_t move)
  73. {
  74.     angle >>= ANGLETOFINESHIFT;
  75.     if(player->powers[pw_flight] && !(player->mo->z <= player->mo->floorz))
  76.     {
  77.         player->mo->momx += FixedMul(move, finecosine[angle]);
  78.         player->mo->momy += FixedMul(move, finesine[angle]);
  79.     }
  80.     else if(P_GetThingFloorType(player->mo) == FLOOR_ICE) // Friction_Low
  81.     {
  82.         player->mo->momx += FixedMul(move>>1, finecosine[angle]);
  83.         player->mo->momy += FixedMul(move>>1, finesine[angle]);
  84.     }
  85.     else
  86.     {
  87.         player->mo->momx += FixedMul(move, finecosine[angle]);
  88.         player->mo->momy += FixedMul(move, finesine[angle]);
  89.     }
  90. }
  91.  
  92.  
  93. /*
  94. ==================
  95. =
  96. = P_CalcHeight
  97. =
  98. =
  99. Calculate the walking / running height adjustment
  100. =
  101. ==================
  102. */
  103.  
  104. void P_CalcHeight (player_t *player)
  105. {
  106.     int        angle;
  107.     fixed_t    bob;
  108.  
  109. //
  110. // regular movement bobbing (needs to be calculated for gun swing even
  111. // if not on ground)
  112. // OPTIMIZE: tablify angle
  113.  
  114.     player->bob = FixedMul (player->mo->momx, player->mo->momx)+
  115.     FixedMul (player->mo->momy,player->mo->momy);
  116.     player->bob >>= 2;
  117.     if (player->bob>MAXBOB)
  118.         player->bob = MAXBOB;
  119.     if(player->mo->flags2&MF2_FLY && !onground)
  120.     {
  121.         player->bob = FRACUNIT/2;
  122.     }    
  123.     
  124.     if ((player->cheats & CF_NOMOMENTUM))
  125.     {
  126.         player->viewz = player->mo->z + VIEWHEIGHT;
  127.         if (player->viewz > player->mo->ceilingz-4*FRACUNIT)
  128.             player->viewz = player->mo->ceilingz-4*FRACUNIT;
  129.         player->viewz = player->mo->z + player->viewheight;
  130.         return;
  131.     }
  132.  
  133.     angle = (FINEANGLES/20*leveltime)&FINEMASK;
  134.     bob = FixedMul ( player->bob/2, finesine[angle]);
  135.  
  136. //
  137. // move viewheight
  138. //
  139.     if (player->playerstate == PST_LIVE)
  140.     {
  141.         player->viewheight += player->deltaviewheight;
  142.         if (player->viewheight > VIEWHEIGHT)
  143.         {
  144.             player->viewheight = VIEWHEIGHT;
  145.             player->deltaviewheight = 0;
  146.         }
  147.         if (player->viewheight < VIEWHEIGHT/2)
  148.         {
  149.             player->viewheight = VIEWHEIGHT/2;
  150.             if (player->deltaviewheight <= 0)
  151.                 player->deltaviewheight = 1;
  152.         }
  153.  
  154.         if (player->deltaviewheight)
  155.         {
  156.             player->deltaviewheight += FRACUNIT/4;
  157.             if (!player->deltaviewheight)
  158.                 player->deltaviewheight = 1;
  159.         }
  160.     }
  161.  
  162.     if(player->morphTics)
  163.     {
  164.         player->viewz = player->mo->z+player->viewheight-(20*FRACUNIT);
  165.     }
  166.     else
  167.     {
  168.         player->viewz = player->mo->z+player->viewheight+bob;
  169.     }
  170.     if(player->mo->floorclip && player->playerstate != PST_DEAD
  171.         && player->mo->z <= player->mo->floorz)
  172.     {
  173.         player->viewz -= player->mo->floorclip;
  174.     }
  175.     if(player->viewz > player->mo->ceilingz-4*FRACUNIT)
  176.     {
  177.         player->viewz = player->mo->ceilingz-4*FRACUNIT;
  178.     }
  179.     if(player->viewz < player->mo->floorz+4*FRACUNIT)
  180.     {
  181.         player->viewz = player->mo->floorz+4*FRACUNIT;
  182.     }
  183. }
  184.  
  185. /*
  186. =================
  187. =
  188. = P_MovePlayer
  189. =
  190. =================
  191. */
  192.  
  193. void P_MovePlayer(player_t *player)
  194. {
  195.     int look;
  196.     int fly;
  197.     ticcmd_t *cmd;
  198.  
  199.     cmd = &player->cmd;
  200.     player->mo->angle += (cmd->angleturn<<16);
  201.  
  202.     onground = (player->mo->z <= player->mo->floorz
  203.         || (player->mo->flags2&MF2_ONMOBJ));
  204.  
  205.     if(cmd->forwardmove)
  206.     {
  207.         if(onground || player->mo->flags2&MF2_FLY)
  208.         {
  209.             P_Thrust(player, player->mo->angle, cmd->forwardmove*2048);
  210.         }
  211.         else
  212.         {
  213.             P_Thrust(player, player->mo->angle, FRACUNIT>>8);
  214.         }
  215.     }    
  216.     if(cmd->sidemove)
  217.     {
  218.         if(onground || player->mo->flags2&MF2_FLY)
  219.             {
  220.             P_Thrust(player, player->mo->angle-ANG90, cmd->sidemove*2048);
  221.         }
  222.         else
  223.         {
  224.             P_Thrust(player, player->mo->angle, FRACUNIT>>8);
  225.         }
  226.     }
  227.     if(cmd->forwardmove || cmd->sidemove)
  228.     {
  229.         if(player->mo->state == &states[PStateNormal[player->class]])
  230.         {
  231.             P_SetMobjState(player->mo, PStateRun[player->class]);
  232.         }
  233.     }
  234.  
  235.     look = cmd->lookfly&15;
  236.     if(look > 7)
  237.     {
  238.         look -= 16;
  239.     }
  240.     if(look)
  241.     {
  242.         if(look == TOCENTER)
  243.         {
  244.             player->centering = true;
  245.         }
  246.         else
  247.         {
  248.             player->lookdir += 5*look;
  249.             if(player->lookdir > 90 || player->lookdir < -110)
  250.             {
  251.                 player->lookdir -= 5*look;
  252.             }
  253.         }
  254.     }
  255.     if(player->centering)
  256.     {
  257.         if(player->lookdir > 0)
  258.         {
  259.             player->lookdir -= 8;
  260.         }
  261.         else if(player->lookdir < 0)
  262.         {
  263.             player->lookdir += 8;
  264.         }
  265.         if(abs(player->lookdir) < 8)
  266.         {
  267.             player->lookdir = 0;
  268.             player->centering = false;
  269.         }
  270.     }
  271.     fly = cmd->lookfly>>4;
  272.     if(fly > 7)
  273.     {
  274.         fly -= 16;
  275.     }
  276.     if(fly && player->powers[pw_flight])
  277.     {
  278.         if(fly != TOCENTER)
  279.         {
  280.             player->flyheight = fly*2;
  281.             if(!(player->mo->flags2&MF2_FLY))
  282.             {
  283.                 player->mo->flags2 |= MF2_FLY;
  284.                 player->mo->flags |= MF_NOGRAVITY;
  285.                 if(player->mo->momz <= -39*FRACUNIT)
  286.                 { // stop falling scream
  287.                     S_StopSound(player->mo);
  288.                 }
  289.             }
  290.         }
  291.         else
  292.         {
  293.             player->mo->flags2 &= ~MF2_FLY;
  294.             player->mo->flags &= ~MF_NOGRAVITY;
  295.         }
  296.     }
  297.     else if(fly > 0)
  298.     {
  299.         P_PlayerUseArtifact(player, arti_fly);
  300.     }
  301.     if(player->mo->flags2&MF2_FLY)
  302.     {
  303.         player->mo->momz = player->flyheight*FRACUNIT;
  304.         if(player->flyheight)
  305.         {
  306.             player->flyheight /= 2;
  307.         }
  308.     }
  309. }
  310.  
  311. //==========================================================================
  312. //
  313. // P_DeathThink
  314. //
  315. //==========================================================================
  316.  
  317. void P_DeathThink(player_t *player)
  318. {
  319.     int dir;
  320.     angle_t delta;
  321.     int lookDelta;
  322.     extern int inv_ptr;
  323.     extern int curpos;
  324.  
  325.     P_MovePsprites(player);
  326.  
  327.     onground = (player->mo->z <= player->mo->floorz);
  328.     if(player->mo->type == MT_BLOODYSKULL || player->mo->type == MT_ICECHUNK)
  329.     { // Flying bloody skull or flying ice chunk
  330.         player->viewheight = 6*FRACUNIT;
  331.         player->deltaviewheight = 0;
  332.         //player->damagecount = 20;
  333.         if(onground)
  334.         {
  335.             if(player->lookdir < 60)
  336.             {
  337.                 lookDelta = (60-player->lookdir)/8;
  338.                 if(lookDelta < 1 && (leveltime&1))
  339.                 {
  340.                     lookDelta = 1;
  341.                 }
  342.                 else if(lookDelta > 6)
  343.                 {
  344.                     lookDelta = 6;
  345.                 }
  346.                 player->lookdir += lookDelta;
  347.             }
  348.         }
  349.     }
  350.     else if(!(player->mo->flags2&MF2_ICEDAMAGE))
  351.     { // Fall to ground (if not frozen)
  352.         player->deltaviewheight = 0;
  353.         if(player->viewheight > 6*FRACUNIT)
  354.         {
  355.             player->viewheight -= FRACUNIT;
  356.         }
  357.         if(player->viewheight < 6*FRACUNIT)
  358.         {
  359.             player->viewheight = 6*FRACUNIT;
  360.         }
  361.         if(player->lookdir > 0)
  362.         {
  363.             player->lookdir -= 6;
  364.         }
  365.         else if(player->lookdir < 0)
  366.         {
  367.             player->lookdir += 6;
  368.         }
  369.         if(abs(player->lookdir) < 6)
  370.         {
  371.             player->lookdir = 0;
  372.         }
  373.     }
  374.     P_CalcHeight(player);
  375.  
  376.     if(player->attacker && player->attacker != player->mo)
  377.     { // Watch killer
  378.         dir = P_FaceMobj(player->mo, player->attacker, &delta);
  379.         if(delta < ANGLE_1*10)
  380.         { // Looking at killer, so fade damage and poison counters
  381.             if(player->damagecount)
  382.             {
  383.                 player->damagecount--;
  384.             }
  385.             if(player->poisoncount)
  386.             {
  387.                 player->poisoncount--;
  388.             }
  389.         }
  390.         delta = delta/8;
  391.         if(delta > ANGLE_1*5)
  392.         {
  393.             delta = ANGLE_1*5;
  394.         }
  395.         if(dir)
  396.         { // Turn clockwise
  397.             player->mo->angle += delta;
  398.         }
  399.         else
  400.         { // Turn counter clockwise
  401.             player->mo->angle -= delta;
  402.         }
  403.     }
  404.     else if(player->damagecount || player->poisoncount)
  405.     {
  406.         if(player->damagecount)
  407.         {
  408.             player->damagecount--;
  409.         }
  410.         else
  411.         {
  412.             player->poisoncount--;
  413.         }
  414.     }
  415.  
  416.     if(player->cmd.buttons&BT_USE)
  417.     {
  418.         if(player == &players[consoleplayer])
  419.         {
  420.             I_SetPalette((byte *)W_CacheLumpName("PLAYPAL", PU_CACHE));
  421.             inv_ptr = 0;
  422.             curpos = 0;
  423.             newtorch = 0;
  424.             newtorchdelta = 0;
  425.         }
  426.         player->playerstate = PST_REBORN;
  427.         player->mo->special1 = player->class;
  428.         if(player->mo->special1 > 2)
  429.         {
  430.             player->mo->special1 = 0;
  431.         }
  432.         // Let the mobj know the player has entered the reborn state.  Some
  433.         // mobjs need to know when it's ok to remove themselves.
  434.         player->mo->special2 = 666;
  435.     }
  436. }
  437.  
  438. //----------------------------------------------------------------------------
  439. //
  440. // PROC P_MorphPlayerThink
  441. //
  442. //----------------------------------------------------------------------------
  443.  
  444. void P_MorphPlayerThink(player_t *player)
  445. {
  446.     mobj_t *pmo;
  447.  
  448.     if(player->morphTics&15)
  449.     {
  450.         return;
  451.     }
  452.     pmo = player->mo;
  453.     if(!(pmo->momx+pmo->momy) && P_Random() < 64)
  454.     { // Snout sniff
  455.         P_SetPspriteNF(player, ps_weapon, S_SNOUTATK2);
  456.         S_StartSound(pmo, SFX_PIG_ACTIVE1); // snort
  457.         return;
  458.     }
  459.     if(P_Random() < 48)
  460.     {
  461.         if(P_Random() < 128)
  462.         {
  463.             S_StartSound(pmo, SFX_PIG_ACTIVE1);
  464.         }
  465.         else
  466.         {
  467.             S_StartSound(pmo, SFX_PIG_ACTIVE2);
  468.         }
  469.     }        
  470. }
  471.  
  472. //----------------------------------------------------------------------------
  473. //
  474. // FUNC P_GetPlayerNum
  475. //
  476. //----------------------------------------------------------------------------
  477.  
  478. int P_GetPlayerNum(player_t *player)
  479. {
  480.     int i;
  481.  
  482.     for(i = 0; i < MAXPLAYERS; i++)
  483.     {
  484.         if(player == &players[i])
  485.         {
  486.             return(i);
  487.         }
  488.     }
  489.     return(0);
  490. }
  491.  
  492. //----------------------------------------------------------------------------
  493. //
  494. // FUNC P_UndoPlayerMorph
  495. //
  496. //----------------------------------------------------------------------------
  497.  
  498. boolean P_UndoPlayerMorph(player_t *player)
  499. {
  500.     mobj_t *fog;
  501.     mobj_t *mo;
  502.     mobj_t *pmo;
  503.     fixed_t x;
  504.     fixed_t y;
  505.     fixed_t z;
  506.     angle_t angle;
  507.     int playerNum;
  508.     weapontype_t weapon;
  509.     int oldFlags;
  510.     int oldFlags2;
  511.     int oldBeast;
  512.  
  513.     pmo = player->mo;
  514.     x = pmo->x;
  515.     y = pmo->y;
  516.     z = pmo->z;
  517.     angle = pmo->angle;
  518.     weapon = pmo->special1;
  519.     oldFlags = pmo->flags;
  520.     oldFlags2 = pmo->flags2;
  521.     oldBeast = pmo->type;
  522.     P_SetMobjState(pmo, S_FREETARGMOBJ);
  523.     playerNum = P_GetPlayerNum(player);
  524.     switch(PlayerClass[playerNum])
  525.     {
  526.         case PCLASS_FIGHTER:
  527.             mo = P_SpawnMobj(x, y, z, MT_PLAYER_FIGHTER);
  528.             break;
  529.         case PCLASS_CLERIC:
  530.             mo = P_SpawnMobj(x, y, z, MT_PLAYER_CLERIC);
  531.             break;
  532.         case PCLASS_MAGE:
  533.             mo = P_SpawnMobj(x, y, z, MT_PLAYER_MAGE);
  534.             break;
  535.         default:
  536.             I_Error("P_UndoPlayerMorph:  Unknown player class %d\n", 
  537.                 player->class);
  538.     }
  539.     if(P_TestMobjLocation(mo) == false)
  540.     { // Didn't fit
  541.         P_RemoveMobj(mo);
  542.         mo = P_SpawnMobj(x, y, z, oldBeast);
  543.         mo->angle = angle;
  544.         mo->health = player->health;
  545.         mo->special1 = weapon;
  546.         mo->player = player;
  547.         mo->flags = oldFlags;
  548.         mo->flags2 = oldFlags2;
  549.         player->mo = mo;
  550.         player->morphTics = 2*35;
  551.         return(false);
  552.     }
  553.     if(player->class == PCLASS_FIGHTER)
  554.     { 
  555.         // The first type should be blue, and the third should be the
  556.         // Fighter's original gold color
  557.         if(playerNum == 0)
  558.         {
  559.             mo->flags |= 2<<MF_TRANSSHIFT;
  560.         }
  561.         else if(playerNum != 2)
  562.         {
  563.             mo->flags |= playerNum<<MF_TRANSSHIFT;
  564.         }
  565.     }
  566.     else if(playerNum)
  567.     { // Set color translation bits for player sprites
  568.         mo->flags |= playerNum<<MF_TRANSSHIFT;
  569.     }
  570.     mo->angle = angle;
  571.     mo->player = player;
  572.     mo->reactiontime = 18;
  573.     if(oldFlags2&MF2_FLY)
  574.     {
  575.         mo->flags2 |= MF2_FLY;
  576.         mo->flags |= MF_NOGRAVITY;
  577.     }
  578.     player->morphTics = 0;
  579.     player->health = mo->health = MAXHEALTH;
  580.     player->mo = mo;
  581.     player->class = PlayerClass[playerNum];
  582.     angle >>= ANGLETOFINESHIFT;
  583.     fog = P_SpawnMobj(x+20*finecosine[angle],
  584.         y+20*finesine[angle], z+TELEFOGHEIGHT, MT_TFOG);
  585.     S_StartSound(fog, SFX_TELEPORT);
  586.     P_PostMorphWeapon(player, weapon);
  587.     return(true);
  588. }
  589.  
  590.  
  591. //----------------------------------------------------------------------------
  592. //
  593. // PROC P_PlayerThink
  594. //
  595. //----------------------------------------------------------------------------
  596.  
  597. void P_PlayerThink(player_t *player)
  598. {
  599.     ticcmd_t *cmd;
  600.     weapontype_t newweapon;
  601.     int floorType;        
  602.     mobj_t *pmo;        
  603.     
  604.     // No-clip cheat
  605.     if(player->cheats&CF_NOCLIP)
  606.     {
  607.         player->mo->flags |= MF_NOCLIP;
  608.     }
  609.     else
  610.     {
  611.         player->mo->flags &= ~MF_NOCLIP;
  612.     }
  613.     cmd = &player->cmd;
  614.     if(player->mo->flags&MF_JUSTATTACKED)
  615.     { // Gauntlets attack auto forward motion
  616.         cmd->angleturn = 0;
  617.         cmd->forwardmove = 0xc800/512;
  618.         cmd->sidemove = 0;
  619.         player->mo->flags &= ~MF_JUSTATTACKED;
  620.     }
  621. // messageTics is above the rest of the counters so that messages will 
  622. //         go away, even in death.
  623.     player->messageTics--; // Can go negative
  624.     if(!player->messageTics || player->messageTics == -1)
  625.     { // Refresh the screen when a message goes away
  626.         player->ultimateMessage = false; // clear out any chat messages.
  627.         player->yellowMessage = false;
  628.         if(player == &players[consoleplayer])
  629.         {
  630.             BorderTopRefresh = true;
  631.         }
  632.     }
  633.     player->worldTimer++;
  634.     if(player->playerstate == PST_DEAD)
  635.     {
  636.         P_DeathThink(player);
  637.         return;
  638.     }
  639.     if(player->jumpTics)
  640.     {
  641.         player->jumpTics--;
  642.     }
  643.     if(player->morphTics)
  644.     {
  645.         P_MorphPlayerThink(player);
  646.     }
  647.     // Handle movement
  648.     if(player->mo->reactiontime)
  649.     { // Player is frozen
  650.         player->mo->reactiontime--;
  651.     }
  652.     else
  653.     {
  654.         P_MovePlayer(player);
  655.         pmo = player->mo;
  656.         if(player->powers[pw_speed] && !(leveltime&1)
  657.             && P_AproxDistance(pmo->momx, pmo->momy) > 12*FRACUNIT)
  658.         {
  659.             mobj_t *speedMo;
  660.             int playerNum;
  661.  
  662.             speedMo = P_SpawnMobj(pmo->x, pmo->y, pmo->z, MT_PLAYER_SPEED);
  663.             if(speedMo)
  664.             {
  665.                 speedMo->angle = pmo->angle;
  666.                 playerNum = P_GetPlayerNum(player);
  667.                 if(player->class == PCLASS_FIGHTER)
  668.                 { 
  669.                     // The first type should be blue, and the 
  670.                     // third should be the Fighter's original gold color
  671.                     if(playerNum == 0)
  672.                     {
  673.                         speedMo->flags |= 2<<MF_TRANSSHIFT;
  674.                     }
  675.                     else if(playerNum != 2)
  676.                     {
  677.                         speedMo->flags |= playerNum<<MF_TRANSSHIFT;
  678.                     }
  679.                 }
  680.                 else if(playerNum)
  681.                 { // Set color translation bits for player sprites
  682.                     speedMo->flags |= playerNum<<MF_TRANSSHIFT;
  683.                 }
  684.                 speedMo->target = pmo;
  685.                 speedMo->special1 = player->class;
  686.                 if(speedMo->special1 > 2)
  687.                 {
  688.                     speedMo->special1 = 0;
  689.                 }
  690.                 speedMo->sprite = pmo->sprite;
  691.                 speedMo->floorclip = pmo->floorclip;
  692.                 if(player == &players[consoleplayer])
  693.                 {
  694.                     speedMo->flags2 |= MF2_DONTDRAW;
  695.                 }
  696.             }
  697.         }
  698.     }
  699.     P_CalcHeight(player);
  700.     if(player->mo->subsector->sector->special)
  701.     {
  702.         P_PlayerInSpecialSector(player);
  703.     }
  704.     if((floorType = P_GetThingFloorType(player->mo)) != FLOOR_SOLID)
  705.     {
  706.         P_PlayerOnSpecialFlat(player, floorType);
  707.     }
  708.     switch(player->class)
  709.     {
  710.         case PCLASS_FIGHTER:
  711.             if(player->mo->momz <= -35*FRACUNIT 
  712.                 && player->mo->momz >= -40*FRACUNIT && !player->morphTics
  713.                 && !S_GetSoundPlayingInfo(player->mo,
  714.                 SFX_PLAYER_FIGHTER_FALLING_SCREAM))
  715.                 {
  716.                     S_StartSound(player->mo, 
  717.                         SFX_PLAYER_FIGHTER_FALLING_SCREAM);
  718.                 }
  719.             break;
  720.         case PCLASS_CLERIC:
  721.             if(player->mo->momz <= -35*FRACUNIT 
  722.                 && player->mo->momz >= -40*FRACUNIT && !player->morphTics
  723.                 && !S_GetSoundPlayingInfo(player->mo,
  724.                 SFX_PLAYER_CLERIC_FALLING_SCREAM))
  725.                 {
  726.                     S_StartSound(player->mo, 
  727.                         SFX_PLAYER_CLERIC_FALLING_SCREAM);
  728.                 }
  729.             break;
  730.         case PCLASS_MAGE:
  731.             if(player->mo->momz <= -35*FRACUNIT 
  732.                 && player->mo->momz >= -40*FRACUNIT && !player->morphTics
  733.                 && !S_GetSoundPlayingInfo(player->mo,
  734.                 SFX_PLAYER_MAGE_FALLING_SCREAM))
  735.                 {
  736.                     S_StartSound(player->mo, 
  737.                         SFX_PLAYER_MAGE_FALLING_SCREAM);
  738.                 }
  739.             break;
  740.         default:
  741.             break;
  742.     }
  743.     if(cmd->arti)
  744.     { // Use an artifact
  745.         if((cmd->arti&AFLAG_JUMP) && onground && !player->jumpTics)
  746.         {
  747.             if(player->morphTics)
  748.             {
  749.                 player->mo->momz = 6*FRACUNIT;
  750.             }
  751.             else 
  752.             {
  753.                 player->mo->momz = 9*FRACUNIT;
  754.             }
  755.             player->mo->flags2 &= ~MF2_ONMOBJ;
  756.             player->jumpTics = 18; 
  757.         }
  758.         else if(cmd->arti&AFLAG_SUICIDE)
  759.         {
  760.             P_DamageMobj(player->mo, NULL, NULL, 10000);
  761.         }
  762.         if(cmd->arti == NUMARTIFACTS)
  763.         { // use one of each artifact (except puzzle artifacts)
  764.             int i;
  765.  
  766.             for(i = 1; i < arti_firstpuzzitem; i++)
  767.             {
  768.                 P_PlayerUseArtifact(player, i);
  769.             }
  770.         }
  771.         else
  772.         {
  773.             P_PlayerUseArtifact(player, cmd->arti&AFLAG_MASK);
  774.         }
  775.     }
  776.     // Check for weapon change
  777.     if(cmd->buttons&BT_SPECIAL)
  778.     { // A special event has no other buttons
  779.         cmd->buttons = 0;
  780.     }
  781.     if(cmd->buttons&BT_CHANGE && !player->morphTics)
  782.     {
  783.         // The actual changing of the weapon is done when the weapon
  784.         // psprite can do it (A_WeaponReady), so it doesn't happen in
  785.         // the middle of an attack.
  786.         newweapon = (cmd->buttons&BT_WEAPONMASK)>>BT_WEAPONSHIFT;
  787.         if(player->weaponowned[newweapon]
  788.             && newweapon != player->readyweapon)
  789.         {
  790.             player->pendingweapon = newweapon;
  791.         }
  792.     }
  793.     // Check for use
  794.     if(cmd->buttons&BT_USE)
  795.     {
  796.         if(!player->usedown)
  797.         {
  798.             P_UseLines(player);
  799.             player->usedown = true;
  800.         }
  801.     }
  802.     else
  803.     {
  804.         player->usedown = false;
  805.     }
  806.     // Morph counter
  807.     if(player->morphTics)
  808.     {
  809.         if(!--player->morphTics)
  810.         { // Attempt to undo the pig
  811.             P_UndoPlayerMorph(player);
  812.         }
  813.     }
  814.     // Cycle psprites
  815.     P_MovePsprites(player);
  816.     // Other Counters
  817.     if(player->powers[pw_invulnerability])
  818.     {
  819.         if(player->class == PCLASS_CLERIC)
  820.         {
  821.             if(!(leveltime&7) && player->mo->flags&MF_SHADOW
  822.                 && !(player->mo->flags2&MF2_DONTDRAW))
  823.             {
  824.                 player->mo->flags &= ~MF_SHADOW;
  825.                 if(!(player->mo->flags&MF_ALTSHADOW))
  826.                 {
  827.                     player->mo->flags2 |= MF2_DONTDRAW|MF2_NONSHOOTABLE;
  828.                 }
  829.             }
  830.             if(!(leveltime&31))
  831.             {
  832.                 if(player->mo->flags2&MF2_DONTDRAW)
  833.                 {
  834.                     if(!(player->mo->flags&MF_SHADOW))
  835.                     {
  836.                         player->mo->flags |= MF_SHADOW|MF_ALTSHADOW;
  837.                     }
  838.                     else
  839.                     {
  840.                         player->mo->flags2 &= ~(MF2_DONTDRAW|MF2_NONSHOOTABLE);
  841.                     }
  842.                 }
  843.                 else
  844.                 {
  845.                     player->mo->flags |= MF_SHADOW;
  846.                     player->mo->flags &= ~MF_ALTSHADOW;
  847.                 }
  848.             }        
  849.         }
  850.         if(!(--player->powers[pw_invulnerability]))
  851.         {
  852.             player->mo->flags2 &= ~(MF2_INVULNERABLE|MF2_REFLECTIVE);
  853.             if(player->class == PCLASS_CLERIC)
  854.             {
  855.                 player->mo->flags2 &= ~(MF2_DONTDRAW|MF2_NONSHOOTABLE);
  856.                 player->mo->flags &= ~(MF_SHADOW|MF_ALTSHADOW);
  857.             }
  858.         }
  859.     }
  860.     if(player->powers[pw_minotaur])
  861.     {
  862.         player->powers[pw_minotaur]--;
  863.     }
  864.     if(player->powers[pw_infrared])
  865.     {
  866.         player->powers[pw_infrared]--;
  867.     }
  868.     if(player->powers[pw_flight] && netgame)
  869.     {
  870.         if(!--player->powers[pw_flight])
  871.         {
  872.             if(player->mo->z != player->mo->floorz)
  873.             {
  874. #ifdef __WATCOMC__
  875.                 if(!useexterndriver)
  876.                 {
  877.                     player->centering = true;
  878.                 }
  879. #else
  880.                 player->centering = true;
  881. #endif
  882.             }
  883.             player->mo->flags2 &= ~MF2_FLY;
  884.             player->mo->flags &= ~MF_NOGRAVITY;
  885.             BorderTopRefresh = true; //make sure the sprite's cleared out
  886.         }
  887.     }
  888.     if(player->powers[pw_speed])
  889.     {
  890.         player->powers[pw_speed]--;
  891.     }
  892.     if(player->damagecount)
  893.     {
  894.         player->damagecount--;
  895.     }
  896.     if(player->bonuscount)
  897.     {
  898.         player->bonuscount--;
  899.     }
  900.     if(player->poisoncount && !(leveltime&15))
  901.     {
  902.         player->poisoncount -= 5;
  903.         if(player->poisoncount < 0)
  904.         {
  905.             player->poisoncount = 0;
  906.         }
  907.         P_PoisonDamage(player, player->poisoner, 1, true); 
  908.     }
  909.     // Colormaps
  910. //    if(player->powers[pw_invulnerability])
  911. //    {
  912. //        if(player->powers[pw_invulnerability] > BLINKTHRESHOLD
  913. //            || (player->powers[pw_invulnerability]&8))
  914. //        {
  915. //            player->fixedcolormap = INVERSECOLORMAP;
  916. //        }
  917. //        else
  918. //        {
  919. //            player->fixedcolormap = 0;
  920. //        }
  921. //    }
  922. //    else 
  923.     if(player->powers[pw_infrared])
  924.     {
  925.         if (player->powers[pw_infrared] <= BLINKTHRESHOLD)
  926.         {
  927.             if(player->powers[pw_infrared]&8)
  928.             {
  929.                 player->fixedcolormap = 0;
  930.             }
  931.             else
  932.             {
  933.                 player->fixedcolormap = 1;
  934.             }
  935.         }
  936.         else if(!(leveltime&16) && player == &players[consoleplayer])
  937.         {
  938.             if(newtorch)
  939.             {
  940.                 if(player->fixedcolormap+newtorchdelta > 7 
  941.                     || player->fixedcolormap+newtorchdelta < 1
  942.                     || newtorch == player->fixedcolormap)
  943.                 {
  944.                     newtorch = 0;
  945.                 }
  946.                 else
  947.                 {
  948.                     player->fixedcolormap += newtorchdelta;
  949.                 }
  950.             }
  951.             else
  952.             {
  953.                 newtorch = (M_Random()&7)+1;
  954.                 newtorchdelta = (newtorch == player->fixedcolormap) ?
  955.                         0 : ((newtorch > player->fixedcolormap) ? 1 : -1);
  956.             }
  957.         }
  958.     }
  959.     else
  960.     {
  961.         player->fixedcolormap = 0;
  962.     }
  963. }
  964.  
  965. //----------------------------------------------------------------------------
  966. //
  967. // PROC P_ArtiTele
  968. //
  969. //----------------------------------------------------------------------------
  970.  
  971. void P_ArtiTele(player_t *player)
  972. {
  973.     int i;
  974.     int selections;
  975.     fixed_t destX;
  976.     fixed_t destY;
  977.     angle_t destAngle;
  978.  
  979.     if(deathmatch)
  980.     {
  981.         selections = deathmatch_p-deathmatchstarts;
  982.         i = P_Random()%selections;
  983.         destX = deathmatchstarts[i].x<<FRACBITS;
  984.         destY = deathmatchstarts[i].y<<FRACBITS;
  985.         destAngle = ANG45*(deathmatchstarts[i].angle/45);
  986.     }
  987.     else
  988.     {
  989.         destX = playerstarts[0][0].x<<FRACBITS;
  990.         destY = playerstarts[0][0].y<<FRACBITS;
  991.         destAngle = ANG45*(playerstarts[0][0].angle/45);
  992.     }
  993.     P_Teleport(player->mo, destX, destY, destAngle, true);
  994.     if(player->morphTics)
  995.     { // Teleporting away will undo any morph effects (pig)
  996.         P_UndoPlayerMorph(player);
  997.     }
  998.     //S_StartSound(NULL, sfx_wpnup); // Full volume laugh
  999. }
  1000.  
  1001.  
  1002. //----------------------------------------------------------------------------
  1003. //
  1004. // PROC P_ArtiTeleportOther
  1005. //
  1006. //----------------------------------------------------------------------------
  1007.  
  1008. void P_ArtiTeleportOther(player_t *player)
  1009. {
  1010.     mobj_t *mo;
  1011.  
  1012.     mo=P_SpawnPlayerMissile(player->mo, MT_TELOTHER_FX1);
  1013.     if (mo)
  1014.     {
  1015.         mo->target = player->mo;
  1016.     }
  1017. }
  1018.  
  1019.  
  1020. void P_TeleportToPlayerStarts(mobj_t *victim)
  1021. {
  1022.     int i,selections=0;
  1023.     fixed_t destX,destY;
  1024.     angle_t destAngle;
  1025.  
  1026.     for (i=0;i<MAXPLAYERS;i++)
  1027.     {
  1028.         if (!playeringame[i]) continue;
  1029.         selections++;
  1030.     }
  1031.     i = P_Random()%selections;
  1032.     destX = playerstarts[0][i].x<<FRACBITS;
  1033.     destY = playerstarts[0][i].y<<FRACBITS;
  1034.     destAngle = ANG45*(playerstarts[0][i].angle/45);
  1035.     P_Teleport(victim, destX, destY, destAngle, true);
  1036.     //S_StartSound(NULL, sfx_wpnup); // Full volume laugh
  1037. }
  1038.  
  1039. void P_TeleportToDeathmatchStarts(mobj_t *victim)
  1040. {
  1041.     int i,selections;
  1042.     fixed_t destX,destY;
  1043.     angle_t destAngle;
  1044.  
  1045.     selections = deathmatch_p-deathmatchstarts;
  1046.     if (selections)
  1047.     {
  1048.         i = P_Random()%selections;
  1049.         destX = deathmatchstarts[i].x<<FRACBITS;
  1050.         destY = deathmatchstarts[i].y<<FRACBITS;
  1051.         destAngle = ANG45*(deathmatchstarts[i].angle/45);
  1052.         P_Teleport(victim, destX, destY, destAngle, true);
  1053.         //S_StartSound(NULL, sfx_wpnup); // Full volume laugh
  1054.     }
  1055.     else
  1056.     {
  1057.          P_TeleportToPlayerStarts(victim);
  1058.     }
  1059. }
  1060.  
  1061.  
  1062.  
  1063. //----------------------------------------------------------------------------
  1064. //
  1065. // PROC P_TeleportOther
  1066. //
  1067. //----------------------------------------------------------------------------
  1068. void P_TeleportOther(mobj_t *victim)
  1069. {
  1070.     if (victim->player)
  1071.     {
  1072.         if (deathmatch)
  1073.             P_TeleportToDeathmatchStarts(victim);
  1074.         else
  1075.             P_TeleportToPlayerStarts(victim);
  1076.     }
  1077.     else
  1078.     {
  1079.         // If death action, run it upon teleport
  1080.         if (victim->flags&MF_COUNTKILL && victim->special)
  1081.         {
  1082.             P_RemoveMobjFromTIDList(victim);
  1083.             P_ExecuteLineSpecial(victim->special, victim->args,
  1084.                     NULL, 0, victim);
  1085.             victim->special = 0;
  1086.         }
  1087.  
  1088.         // Send all monsters to deathmatch spots
  1089.         P_TeleportToDeathmatchStarts(victim);
  1090.     }
  1091. }
  1092.  
  1093.  
  1094.  
  1095. #define BLAST_RADIUS_DIST    255*FRACUNIT
  1096. #define BLAST_SPEED            20*FRACUNIT
  1097. #define BLAST_FULLSTRENGTH    255
  1098.  
  1099. void ResetBlasted(mobj_t *mo)
  1100. {
  1101.     mo->flags2 &= ~MF2_BLASTED;
  1102.     if (!(mo->flags&MF_ICECORPSE))
  1103.     {
  1104.         mo->flags2 &= ~MF2_SLIDE;
  1105.     }
  1106. }
  1107.  
  1108. void P_BlastMobj(mobj_t *source, mobj_t *victim, fixed_t strength)
  1109. {
  1110.     angle_t angle,ang;
  1111.     mobj_t *mo;
  1112.     fixed_t x,y,z;
  1113.  
  1114.     angle = R_PointToAngle2(source->x, source->y, victim->x, victim->y);
  1115.     angle >>= ANGLETOFINESHIFT;
  1116.     if (strength < BLAST_FULLSTRENGTH)
  1117.     {
  1118.         victim->momx = FixedMul(strength, finecosine[angle]);
  1119.         victim->momy = FixedMul(strength, finesine[angle]);
  1120.         if (victim->player)
  1121.         {
  1122.             // Players handled automatically
  1123.         }
  1124.         else
  1125.         {
  1126.             victim->flags2 |= MF2_SLIDE;
  1127.             victim->flags2 |= MF2_BLASTED;
  1128.         }
  1129.     }
  1130.     else        // full strength blast from artifact
  1131.     {
  1132.         if (victim->flags&MF_MISSILE)
  1133.         {
  1134.             switch(victim->type)
  1135.             {
  1136.                 case MT_SORCBALL1:    // don't blast sorcerer balls
  1137.                 case MT_SORCBALL2:
  1138.                 case MT_SORCBALL3:
  1139.                     return;
  1140.                     break;
  1141.                 case MT_MSTAFF_FX2:    // Reflect to originator
  1142.                     victim->special1 = (int)victim->target;    
  1143.                     victim->target = source;
  1144.                     break;
  1145.                 default:
  1146.                     break;
  1147.             }
  1148.         }
  1149.         if (victim->type == MT_HOLY_FX)
  1150.         {
  1151.             if ((mobj_t *)(victim->special1) == source)
  1152.             {
  1153.                 victim->special1 = (int)victim->target;    
  1154.                 victim->target = source;
  1155.             }
  1156.         }
  1157.         victim->momx = FixedMul(BLAST_SPEED, finecosine[angle]);
  1158.         victim->momy = FixedMul(BLAST_SPEED, finesine[angle]);
  1159.  
  1160.         // Spawn blast puff
  1161.         ang = R_PointToAngle2(victim->x, victim->y, source->x, source->y);
  1162.         ang >>= ANGLETOFINESHIFT;
  1163.         x = victim->x + FixedMul(victim->radius+FRACUNIT, finecosine[ang]);
  1164.         y = victim->y + FixedMul(victim->radius+FRACUNIT, finesine[ang]);
  1165.         z = victim->z - victim->floorclip + (victim->height>>1);
  1166.         mo=P_SpawnMobj(x, y, z, MT_BLASTEFFECT);
  1167.         if (mo)
  1168.         {
  1169.             mo->momx = victim->momx;
  1170.             mo->momy = victim->momy;
  1171.         }
  1172.  
  1173.         if (victim->flags&MF_MISSILE)
  1174.         {
  1175.             victim->momz = 8*FRACUNIT;
  1176.             mo->momz = victim->momz;
  1177.         }
  1178.         else
  1179.         {
  1180.             victim->momz = (1000/victim->info->mass)<<FRACBITS;
  1181.         }
  1182.         if (victim->player)
  1183.         {
  1184.             // Players handled automatically
  1185.         }
  1186.         else
  1187.         {
  1188.             victim->flags2 |= MF2_SLIDE;
  1189.             victim->flags2 |= MF2_BLASTED;
  1190.         }
  1191.     }
  1192. }
  1193.  
  1194.  
  1195. // Blast all mobj things away
  1196. void P_BlastRadius(player_t *player)
  1197. {
  1198.     mobj_t *mo;
  1199.     mobj_t *pmo=player->mo;
  1200.     thinker_t *think;
  1201.     fixed_t dist;
  1202.  
  1203.     S_StartSound(pmo, SFX_ARTIFACT_BLAST);
  1204.     P_NoiseAlert(player->mo, player->mo);
  1205.  
  1206.     for(think = thinkercap.next; think != &thinkercap; think = think->next)
  1207.     {
  1208.         if(think->function != P_MobjThinker)
  1209.         { // Not a mobj thinker
  1210.             continue;
  1211.         }
  1212.         mo = (mobj_t *)think;
  1213.         if((mo == pmo) || (mo->flags2&MF2_BOSS))
  1214.         { // Not a valid monster
  1215.             continue;
  1216.         }
  1217.         if ((mo->type == MT_POISONCLOUD) ||        // poison cloud
  1218.             (mo->type == MT_HOLY_FX) ||            // holy fx
  1219.             (mo->flags&MF_ICECORPSE))            // frozen corpse
  1220.         {
  1221.             // Let these special cases go
  1222.         }
  1223.         else if ((mo->flags&MF_COUNTKILL) &&
  1224.             (mo->health <= 0))
  1225.         {
  1226.             continue;
  1227.         }
  1228.         else if (!(mo->flags&MF_COUNTKILL) &&
  1229.             !(mo->player) &&
  1230.             !(mo->flags&MF_MISSILE))
  1231.         {    // Must be monster, player, or missile
  1232.             continue;
  1233.         }
  1234.         if (mo->flags2&MF2_DORMANT)
  1235.         {
  1236.             continue;        // no dormant creatures
  1237.         }
  1238.         if ((mo->type == MT_WRAITHB) && (mo->flags2&MF2_DONTDRAW))
  1239.         {
  1240.             continue;        // no underground wraiths
  1241.         }
  1242.         if ((mo->type == MT_SPLASHBASE) ||
  1243.             (mo->type == MT_SPLASH))
  1244.         {
  1245.             continue;
  1246.         }
  1247.         if(mo->type == MT_SERPENT || mo->type == MT_SERPENTLEADER)
  1248.         {
  1249.             continue;
  1250.         }
  1251.         dist = P_AproxDistance(pmo->x - mo->x, pmo->y - mo->y);
  1252.         if(dist > BLAST_RADIUS_DIST)
  1253.         { // Out of range
  1254.             continue;
  1255.         }
  1256.         P_BlastMobj(pmo, mo, BLAST_FULLSTRENGTH);
  1257.     }
  1258. }
  1259.  
  1260.  
  1261. #define HEAL_RADIUS_DIST    255*FRACUNIT
  1262.  
  1263. // Do class specific effect for everyone in radius
  1264. boolean P_HealRadius(player_t *player)
  1265. {
  1266.     mobj_t *mo;
  1267.     mobj_t *pmo=player->mo;
  1268.     thinker_t *think;
  1269.     fixed_t dist;
  1270.     int effective=false;
  1271.     int amount;
  1272.  
  1273.     for(think = thinkercap.next; think != &thinkercap; think = think->next)
  1274.     {
  1275.         if(think->function != P_MobjThinker)
  1276.         { // Not a mobj thinker
  1277.             continue;
  1278.         }
  1279.         mo = (mobj_t *)think;
  1280.  
  1281.         if (!mo->player) continue;
  1282.         if (mo->health <= 0) continue;
  1283.         dist = P_AproxDistance(pmo->x - mo->x, pmo->y - mo->y);
  1284.         if(dist > HEAL_RADIUS_DIST)
  1285.         { // Out of range
  1286.             continue;
  1287.         }
  1288.  
  1289.         switch(player->class)
  1290.         {
  1291.             case PCLASS_FIGHTER:        // Radius armor boost
  1292.                 if ((P_GiveArmor(mo->player, ARMOR_ARMOR, 1)) ||
  1293.                     (P_GiveArmor(mo->player, ARMOR_SHIELD, 1)) ||
  1294.                     (P_GiveArmor(mo->player, ARMOR_HELMET, 1)) ||
  1295.                     (P_GiveArmor(mo->player, ARMOR_AMULET, 1)))
  1296.                 {
  1297.                     effective=true;
  1298.                     S_StartSound(mo, SFX_MYSTICINCANT);
  1299.                 }
  1300.                 break;
  1301.             case PCLASS_CLERIC:            // Radius heal
  1302.                 amount = 50 + (P_Random()%50);
  1303.                 if (P_GiveBody(mo->player, amount))
  1304.                 {
  1305.                     effective=true;
  1306.                     S_StartSound(mo, SFX_MYSTICINCANT);
  1307.                 }
  1308.                 break;
  1309.             case PCLASS_MAGE:            // Radius mana boost
  1310.                 amount = 50 + (P_Random()%50);
  1311.                 if ((P_GiveMana(mo->player, MANA_1, amount)) ||
  1312.                     (P_GiveMana(mo->player, MANA_2, amount)))
  1313.                 {
  1314.                     effective=true;
  1315.                     S_StartSound(mo, SFX_MYSTICINCANT);
  1316.                 }
  1317.                 break;
  1318.             case PCLASS_PIG:
  1319.             default:
  1320.                 break;
  1321.         }
  1322.     }
  1323.     return(effective);
  1324. }
  1325.  
  1326.  
  1327. //----------------------------------------------------------------------------
  1328. //
  1329. // PROC P_PlayerNextArtifact
  1330. //
  1331. //----------------------------------------------------------------------------
  1332.  
  1333. void P_PlayerNextArtifact(player_t *player)
  1334. {
  1335.     extern int inv_ptr;
  1336.     extern int curpos;
  1337.  
  1338.     if(player == &players[consoleplayer])
  1339.     {
  1340.         inv_ptr--;
  1341.         if(inv_ptr < 6)
  1342.         {
  1343.             curpos--;
  1344.             if(curpos < 0)
  1345.             {
  1346.                 curpos = 0;
  1347.             }
  1348.         }
  1349.         if(inv_ptr < 0)
  1350.         {
  1351.             inv_ptr = player->inventorySlotNum-1;
  1352.             if(inv_ptr < 6)
  1353.             {
  1354.                 curpos = inv_ptr;
  1355.             }
  1356.             else
  1357.             {
  1358.                 curpos = 6;
  1359.             }
  1360.         }
  1361.         player->readyArtifact =
  1362.             player->inventory[inv_ptr].type;
  1363.     }
  1364. }
  1365.  
  1366. //----------------------------------------------------------------------------
  1367. //
  1368. // PROC P_PlayerRemoveArtifact
  1369. //
  1370. //----------------------------------------------------------------------------
  1371.  
  1372. void P_PlayerRemoveArtifact(player_t *player, int slot)
  1373. {
  1374.     int i;
  1375.     extern int inv_ptr;
  1376.     extern int curpos;
  1377.  
  1378.     player->artifactCount--;
  1379.     if(!(--player->inventory[slot].count))
  1380.     { // Used last of a type - compact the artifact list
  1381.         player->readyArtifact = arti_none;
  1382.         player->inventory[slot].type = arti_none;
  1383.         for(i = slot+1; i < player->inventorySlotNum; i++)
  1384.         {
  1385.             player->inventory[i-1] = player->inventory[i];
  1386.         }
  1387.         player->inventorySlotNum--;
  1388.         if(player == &players[consoleplayer])
  1389.         { // Set position markers and get next readyArtifact
  1390.             inv_ptr--;
  1391.             if(inv_ptr < 6)
  1392.             {
  1393.                 curpos--;
  1394.                 if(curpos < 0)
  1395.                 {
  1396.                     curpos = 0;
  1397.                 }
  1398.             }
  1399.             if(inv_ptr >= player->inventorySlotNum)
  1400.             {
  1401.                 inv_ptr = player->inventorySlotNum-1;
  1402.             }
  1403.             if(inv_ptr < 0)
  1404.             {
  1405.                 inv_ptr = 0;
  1406.             }
  1407.             player->readyArtifact =
  1408.                 player->inventory[inv_ptr].type;
  1409.         }
  1410.     }
  1411. }
  1412.  
  1413. //----------------------------------------------------------------------------
  1414. //
  1415. // PROC P_PlayerUseArtifact
  1416. //
  1417. //----------------------------------------------------------------------------
  1418.  
  1419. void P_PlayerUseArtifact(player_t *player, artitype_t arti)
  1420. {
  1421.     int i;
  1422.  
  1423.     for(i = 0; i < player->inventorySlotNum; i++)
  1424.     {
  1425.         if(player->inventory[i].type == arti)
  1426.         { // Found match - try to use
  1427.             if(P_UseArtifact(player, arti))
  1428.             { // Artifact was used - remove it from inventory
  1429.                 P_PlayerRemoveArtifact(player, i);
  1430.                 if(player == &players[consoleplayer])
  1431.                 {
  1432.                     if(arti < arti_firstpuzzitem)
  1433.                     {
  1434.                         S_StartSound(NULL, SFX_ARTIFACT_USE);
  1435.                     }
  1436.                     else
  1437.                     {
  1438.                         S_StartSound(NULL, SFX_PUZZLE_SUCCESS);
  1439.                     }
  1440.                     ArtifactFlash = 4;
  1441.                 }
  1442.             }
  1443.             else if(arti < arti_firstpuzzitem)
  1444.             { // Unable to use artifact, advance pointer
  1445.                 P_PlayerNextArtifact(player);
  1446.             }
  1447.             break;
  1448.         }
  1449.     }
  1450. }
  1451.  
  1452. //==========================================================================
  1453. //
  1454. // P_UseArtifact
  1455. //
  1456. // Returns true if the artifact was used.
  1457. //
  1458. //==========================================================================
  1459.  
  1460. boolean P_UseArtifact(player_t *player, artitype_t arti)
  1461. {
  1462.     mobj_t *mo;
  1463.     angle_t angle;
  1464.     int i;
  1465.     int count;
  1466.  
  1467.     switch(arti)
  1468.     {
  1469.         case arti_invulnerability:
  1470.             if(!P_GivePower(player, pw_invulnerability))
  1471.             {
  1472.                 return(false);
  1473.             }
  1474.             break;
  1475.         case arti_health:
  1476.             if(!P_GiveBody(player, 25))
  1477.             {
  1478.                 return(false);
  1479.             }
  1480.             break;
  1481.         case arti_superhealth:
  1482.             if(!P_GiveBody(player, 100))
  1483.             {
  1484.                 return(false);
  1485.             }
  1486.             break;
  1487.         case arti_healingradius:
  1488.             if (!P_HealRadius(player))
  1489.             {
  1490.                 return(false);
  1491.             }
  1492.             break;
  1493.         case arti_torch:
  1494.             if(!P_GivePower(player, pw_infrared))
  1495.             {
  1496.                 return(false);
  1497.             }
  1498.             break;
  1499.         case arti_egg:
  1500.             mo = player->mo;
  1501.             P_SpawnPlayerMissile(mo, MT_EGGFX);
  1502.             P_SPMAngle(mo, MT_EGGFX, mo->angle-(ANG45/6));
  1503.             P_SPMAngle(mo, MT_EGGFX, mo->angle+(ANG45/6));
  1504.             P_SPMAngle(mo, MT_EGGFX, mo->angle-(ANG45/3));
  1505.             P_SPMAngle(mo, MT_EGGFX, mo->angle+(ANG45/3));
  1506.             break;
  1507.         case arti_fly:
  1508.             if(!P_GivePower(player, pw_flight))
  1509.             {
  1510.                 return(false);
  1511.             }
  1512.             if(player->mo->momz <= -35*FRACUNIT)
  1513.             { // stop falling scream
  1514.                 S_StopSound(player->mo);
  1515.             }
  1516.             break;
  1517.         case arti_summon:
  1518.             mo = P_SpawnPlayerMissile(player->mo, MT_SUMMON_FX);
  1519.             if (mo)
  1520.             {
  1521.                 mo->target = player->mo;
  1522.                 mo->special1 = (int)(player->mo);
  1523.                 mo->momz = 5*FRACUNIT;
  1524.             }
  1525.             break;
  1526.         case arti_teleport:
  1527.             P_ArtiTele(player);
  1528.             break;
  1529.         case arti_teleportother:
  1530.             P_ArtiTeleportOther(player);
  1531.             break;
  1532.         case arti_poisonbag:
  1533.             angle = player->mo->angle>>ANGLETOFINESHIFT;
  1534.             if(player->class == PCLASS_CLERIC)
  1535.             {
  1536.                 mo = P_SpawnMobj(player->mo->x+16*finecosine[angle],
  1537.                     player->mo->y+24*finesine[angle], player->mo->z-
  1538.                     player->mo->floorclip+8*FRACUNIT, MT_POISONBAG);
  1539.                 if(mo)
  1540.                 {
  1541.                     mo->target = player->mo;
  1542.                 }
  1543.             }
  1544.             else if(player->class == PCLASS_MAGE)
  1545.             {
  1546.                 mo = P_SpawnMobj(player->mo->x+16*finecosine[angle],
  1547.                     player->mo->y+24*finesine[angle], player->mo->z-
  1548.                     player->mo->floorclip+8*FRACUNIT, MT_FIREBOMB);
  1549.                 if(mo)
  1550.                 {
  1551.                     mo->target = player->mo;
  1552.                 }
  1553.             }            
  1554.             else // PCLASS_FIGHTER, obviously (also pig, not so obviously)
  1555.             {
  1556.                 mo = P_SpawnMobj(player->mo->x, player->mo->y, 
  1557.                     player->mo->z-player->mo->floorclip+35*FRACUNIT,
  1558.                     MT_THROWINGBOMB);
  1559.                 if(mo)
  1560.                 {
  1561.                     mo->angle = player->mo->angle+(((P_Random()&7)-4)<<24);
  1562.                     mo->momz = 4*FRACUNIT+((player->lookdir)<<(FRACBITS-4));
  1563.                     mo->z += player->lookdir<<(FRACBITS-4);
  1564.                     P_ThrustMobj(mo, mo->angle, mo->info->speed);
  1565.                     mo->momx += player->mo->momx>>1;
  1566.                     mo->momy += player->mo->momy>>1;
  1567.                     mo->target = player->mo;
  1568.                     mo->tics -= P_Random()&3;
  1569.                     P_CheckMissileSpawn(mo);                                            
  1570.                 } 
  1571.             }
  1572.             break;
  1573.         case arti_speed:
  1574.             if(!P_GivePower(player, pw_speed))
  1575.             {
  1576.                 return(false);
  1577.             }
  1578.             break;
  1579.         case arti_boostmana:
  1580.             if(!P_GiveMana(player, MANA_1, MAX_MANA))
  1581.             {
  1582.                 if(!P_GiveMana(player, MANA_2, MAX_MANA))
  1583.                 {
  1584.                     return false;
  1585.                 }
  1586.                 
  1587.             }
  1588.             else 
  1589.             {
  1590.                 P_GiveMana(player, MANA_2, MAX_MANA);
  1591.             }
  1592.             break;
  1593.         case arti_boostarmor:
  1594.             count = 0;
  1595.  
  1596.             for(i = 0; i < NUMARMOR; i++)
  1597.             {
  1598.                 count += P_GiveArmor(player, i, 1); // 1 point per armor type
  1599.             }
  1600.             if(!count)
  1601.             {
  1602.                 return false;
  1603.             }
  1604.             break;
  1605.         case arti_blastradius:
  1606.             P_BlastRadius(player);
  1607.             break;
  1608.  
  1609.         case arti_puzzskull:
  1610.         case arti_puzzgembig:
  1611.         case arti_puzzgemred:
  1612.         case arti_puzzgemgreen1:
  1613.         case arti_puzzgemgreen2:
  1614.         case arti_puzzgemblue1:
  1615.         case arti_puzzgemblue2:
  1616.         case arti_puzzbook1:
  1617.         case arti_puzzbook2:
  1618.         case arti_puzzskull2:
  1619.         case arti_puzzfweapon:
  1620.         case arti_puzzcweapon:
  1621.         case arti_puzzmweapon:
  1622.         case arti_puzzgear1:
  1623.         case arti_puzzgear2:
  1624.         case arti_puzzgear3:
  1625.         case arti_puzzgear4:
  1626.             if(P_UsePuzzleItem(player, arti-arti_firstpuzzitem))
  1627.             {
  1628.                 return true;
  1629.             }
  1630.             else
  1631.             {
  1632.                 P_SetYellowMessage(player, TXT_USEPUZZLEFAILED, false);
  1633.                 return false;
  1634.             }
  1635.             break;
  1636.         default:
  1637.             return false;
  1638.     }
  1639.     return true;
  1640. }
  1641.  
  1642. //============================================================================
  1643. //
  1644. // A_SpeedFade
  1645. //
  1646. //============================================================================
  1647.  
  1648. void A_SpeedFade(mobj_t *actor)
  1649. {
  1650.     actor->flags |= MF_SHADOW;
  1651.     actor->flags &= ~MF_ALTSHADOW;
  1652.     actor->sprite = actor->target->sprite;
  1653. }
  1654.